/**
 * @author ccpalu
 */

function similarity(){
	var proceedAnalysis;
	loadingStatus("Analyzing CNV profiles");//April 2011
	try	{
		var cnv = document.getElementById('CNV');	
		
		switch (document.getElementById("sim_method").value){
		case "0":
			var sample = document.getElementById("choose_sample").value;
			var arrays = document.getElementById('CNV').segData;
			var ch = cnv.ch;
				
			var chDistance = new Array(ch.length);
			var similarity = new Array(arrays[ch[0]].length);
			for (var i = 0; i < similarity.length; i = i + 1) {
				similarity[i] = 0;
			}
			var index = new Array(similarity.length);
			
			for (var i = 0; i < similarity.length; i = i + 1) {
				index[i] = i;
			}
				
			var targetArray;
			var distance = quickSortIndex(similarity, index);
			distance[2] = new Array();
			
			var position;
			var opt = document.getElementById('choose_sample').options;
				
			for (var i = 0; i < distance[1].length; i = i + 1) {
				position = findInArray(opt, distance[1][(i)], 'value');	
				try {
					distance[2][i] = opt[position].innerHTML;
				} 
				catch (e) {
					distance[2][i] = 'option' + (i + 1);
				}
			}
			loadingStatus("Plotting CNV ...");
			distanceChart(distance);
			proceedAnalysis=false;
			break;
		case "PWD":
			if (cnv.xAxis.length == 0) {
				alert('The "Probe Weithed Distance" needs a Probe Map.\nPlease, upload a probe map or choose another method.');
				proceedAnalysis = false;
			}
			else { // if (cnv.xAxis.length == 0)
				var chSelect = chSelected();
				var chMissing = new Array();
				for (var i=0, j=0; i < chSelect.length; i++){
					if (cnv.xAxis[chSelect[i]]==undefined){
						chMissing[j]=chSelect[i];
						j++;
					}
				}
				if (chMissing.length){
					var chString = 'The probe map for chromosome';
					if (chMissing.length>1){
						chString = chString +'s';
					}
					chString = chString +' ';
					for (i=0; i<chMissing.length; i++){
						chString = chString + chMissing[i] + ' ';
					}
					chString = chString + 'is missing.\nThe Probe Weighted Euclidean Distance can not be applied.';
					alert (chString);
					proceedAnalysis = false;
				}
				else{ //if (chMissing.length)
					proceedAnalysis=true;
				}
			}
			break;
		default:
			proceedAnalysis = true;
		}//switch
		if (proceedAnalysis){
			var sample = document.getElementById("choose_sample").value;
			var arrays = document.getElementById('CNV').segData;
			var ch = cnv.ch;
			
			var chDistance = new Array(ch.length);
			var similarity = new Array(arrays[ch[0]].length);
			for (var i = 0; i < similarity.length; i = i + 1) {
				similarity[i] = 0;
			}
			var index = new Array(similarity.length);
			var entropy, yProbability, numberOfValues;
			var discreatArray = new Array();
			for (var i = 0; i < similarity.length; i = i + 1) {
				index[i] = i;
			}
			
			var targetArray;
					
			for (var i = 0; i < ch.length; i += 1) {
			
				chDistance[i] = new Array();
				for (var j = 0; j < cnv.chRegions[ch[i]].length; j = j + 2) {
					targetArray = especifyArray(arrays[ch[i]][sample], cnv.chRegions[ch[i]][j], cnv.chRegions[ch[i]][1 + j]);
					chDistance[i][(j / 2)] = ch_similarity(targetArray, arrays[ch[i]], ch[i], j + 1);
					for (var k = 0; k < similarity.length; k += 1) {
						similarity[k] = similarity[k] + chDistance[i][j / 2][k] * 1;
					}
				}
				
			}
				
			var distance = quickSortIndex(similarity, index);
			distance[2] = new Array();
			var position;
			var opt = document.getElementById('choose_sample').options;
			
			for (var i = 0; i < distance[1].length; i = i + 1) {
				position = findInArray(opt, distance[1][(i)], 'value');
			
				try {
					distance[2][i] = opt[position].innerHTML;
				} 
				catch (e) {
					distance[2][i] = 'option' + (i + 1);
				}
			}
			loadingStatus("Plotting CNV ...");
			distanceChart(distance);
		}
	}
	catch (e){
		alert(e);
	}
	
	return false;
}

function especifyArray(original,start, end){
	if (!original) {
		extracted = new Array(1);
		extracted.xi = new Array(1);
		extracted.xi[0] = start;
		extracted.xf = new Array(1);
		extracted.xf[0] = end;
		extracted.y = new Array(1);
		extracted.y[0] = 0;
		extracted.color = new Array(1);
		extracted.color[0] = "#FFFFFF";
	}
	else {
		var xiArray = new findInArraySorted(original.xi);
		var xfArray = new findInArraySorted(original.xf);
		var startIndex = xiArray.equalOrSmallerValue(start);
		var endIndex = xfArray.equalOrBiggerValue(end);
		var extracted = new Array();
		extracted.xi = new Array(endIndex-startIndex+1);
		extracted.xf = new Array(endIndex-startIndex+1);
		extracted.y = new Array(endIndex-startIndex+1);
		extracted.color = new Array(endIndex-startIndex+1);
	
		for (var i = startIndex, j = 0; i <= endIndex; i = i + 1, j = j + 1) {
			extracted.xi[j] = original.xi[i];
			extracted.xf[j] = original.xf[i];
			extracted.y[j] = original.y[i];
			extracted.color[j] = original.color[i];
		}
		if (start > extracted.xi[0]) 
			extracted.xi[0] = start;
		if (end < extracted.xf[j - 1]) 
			extracted.xf[j - 1] = end;
	}
	return extracted;
}

function ch_similarity(arr, arrays,ch, r){
	var distance= new Array(arrays.length);
	var arrayInterc, arrayconcensus ;
	if (r)
		var region = document.getElementById('CNV').chRegions[ch];
	if (!arr) {
		arr= new Array(1);
		arr.xi = new Array(1);
		arr.xi[0] = 0;
		arr.xf =new Array(1);
		arr.xf[0] = 0;
		arr.y = new Array(1);					
		arr.y[0] = 0;
		arr.color =new Array(1);
		arr.color[0]="#FFFFFF";
	}
	var arrInterc = intercalate (arr);
	for (var i = 0; i < arrays.length; i += 1) {
		if (r) {
			var arrayTemp = especifyArray(arrays[i], region[r-1], region[r]);
			arrayInterc = intercalate(arrayTemp);
			arrayconcensus = consensus (arrInterc, arrayInterc,arr.y,arrayTemp.y);
		}
		else{
			if (!arrays[i]) {
				arrays[i] = new Array(1);
				arrays[i].xi = new Array(1);
				arrays[i].xi[0] = 0;
				arrays[i].xf = new Array(1);
				arrays[i].xf[0] = 0;
				arrays[i].y = new Array(1);
				arrays[i].y[0] = 0;
				arrays[i].color = new Array(1);
				arrays[i].color[0] = "#FFFFFF";
			}	
		arrayInterc = intercalate(arrays[i]);
		arrayconcensus = consensus (arrInterc, arrayInterc,arr.y,arrays[i].y);
	}
		
		
		if (document.getElementById("sim_method").value == "SED") 
			distance[i] = euclidean(arrayconcensus[1], arrayconcensus[2]);
		else {
			if (document.getElementById("sim_method").value == "PWD") 
				var wheight=weighting(arrayconcensus[0],ch);	
			else	
				var wheight=weightingA(arrayconcensus[0],ch);	
			distance[i] = euclidean(arrayconcensus[1], arrayconcensus[2], wheight);
		}

	}
	return distance;
}

function consensus(arr1, arr2, v1, v2){
	var consens = new Array();
	var val1 = new Array();
	var val2 = new Array();
	var end1 = false, end2 = false;
	var i = 0, j = 0, k = 0;
	while ((i < arr1.length)&&(j < arr2.length)) {
	
		if (arr1[i] == arr2[j]) {
			consens[k] = arr1[i] * 1;
			
			if (k % 2 == 0) {
				val1[k/2] = v1[Math.floor(i/2)];
				val2[k/2] = v2[Math.floor(j/2)];
			}
			
			i = i + 1;
			j = j + 1;
			if (i % 2) 
				end1 = true;
			else 
				end1 = false;
			
			if (j % 2) 
				end2 = true;
			else 
				end2 = false;
			
			
		}
		else {
			if (arr1[i] < arr2[j]) {
				consens[k] = arr1[i] * 1;
				if (k % 2 == 0) {
					
					if (end1&&end2)
						val1[k/2] = 0;
					else	
						val1[k/2] = v1[Math.floor(i/2)];
					
					if (end2) 
						val2[k/2] = v2[Math.floor(j/2)];
					else 
						val2[k/2] = 0;
				}
				if (((k % 2 == 0))||(end1&&!end2)) {
					i = i + 1;
					if (i % 2) 
						end1 = true;
					else 
						end1 = false;
				}
				
			}
			else {
				consens[k] = arr2[j] * 1;
				if (k % 2 == 0) {
					if (end1 && end2)
						val2[k/2] = 0;
					else
						val2[k/2] = v2[Math.floor(j/2)];
					if (end1) 
						val1[k/2] = v1[Math.floor(i/2)];
					else 
						val1[k/2] = 0;
				}
				if (((k % 2 == 0)) || (end2&&!end1)) {
					j = j + 1;
					if (j % 2) 
						end2 = true;
					else 
						end2 = false;
				}
			}
			
		}
		k = k + 1;
		
	}
	if (end1 != end2) {
		if (i < arr1.length) 
			consens[k] = arr1[i];
		else 
			consens[k] = arr2[j];
	}
	return [consens, val1, val2];
}

function intercalate(arr){
	var length = arr.xi.length;
	var interc = new Array (length*2);
	for (var i=0; i< length; i=i+1){
		interc[i*2] = arr.xi[i];
		interc[(i*2)+1] = arr.xf[i];	
	}
	return interc;
}

function euclidean(arr1,arr2,w){
	var	distance=0;
	if (!w) {
		for (var i = 0; i < arr1.length; i += 1) {
			distance += Math.pow(((arr1[i] - arr2[i])), 2);
		}
	}
	else{
		for (var i=0;i<arr1.length;i+=1){
			distance+=((Math.pow((arr1[i]-arr2[i]),2))*w[i]);		
		}
	}
	
	return Math.sqrt(distance);
}

function weighting(index,ch){
	var cnv=document.getElementById('CNV');
	var wheight=new Array();
	var length=cnv.xAxis[ch].length;
	var targetArray= new findInArraySorted(cnv.xAxis[ch]);
	for (var i=0; i<(Math.floor(index.length/2));i+=1){
		wheight[i]=(targetArray.equalOrSmallerValue(index[i*2+1])-targetArray.equalOrBiggerValue(index[i*2])+1);
		if (wheight[i] != 0) {
			wheight[i]=wheight[i]/length;
		}
		
	}
	return wheight;
}
function weightingA(index,ch){
	
	var wheight=new Array();
	var cnv=document.getElementById('CNV');
	var length = cnv.realSize[ch];
	for (var i=0; i<(Math.floor(index.length/2));i+=1){
		wheight[i]=(index[i*2+1]-index[i*2]);
		if (wheight[i] != 0) {
			wheight[i]=wheight[i]/length;
		}		
	}
	
	return wheight;
}


quickSort = function(origArr) {


//http://www.devarticles.com/c/a/JavaScript/Quicksort/
/* Revised by Cintia C.Palu */
  // return if array is unsortable
  
  var arr= copyArray(origArr);
  if (arr.length <= 1){
    return arr;
  }

  var less = Array(), greater = Array();

  // select and remove a pivot value pivot from array
  // a pivot value closer to median of the dataset may result in better performance
  var pivotIndex = Math.floor(arr.length / 2);
  var pivot = (arr.splice(pivotIndex, 1)[0])*1;

  // step through all array elements
  for (var x = 0; x < arr.length; x++){
	arr[x]=arr[x]*1;
    // if (current value is less than pivot),
    // OR if (current value is the same as pivot AND this index is less than the index of the pivot in the original array)
    // then push onto end of less array
    if (
      (arr[x] < pivot)
      ||
      (arr[x] == pivot && x < pivotIndex)  // this maintains the original order of values equal to the pivot
    ){
      less.push(arr[x]);
    }

    // if (current value is greater than pivot),
    // OR if (current value is the same as pivot AND this index is greater than or equal to the index of the pivot in the original array)
    // then push onto end of greater array
    else {
      greater.push(arr[x]);
    }
  }

  // concatenate less+pivot+greater arrays
  return quickSort(less).concat([pivot], quickSort(greater));
};

quickSortIndex = function(origArr, origArrider) {
//http://www.devarticles.com/c/a/JavaScript/Quicksort/
//Alterated by Cintia C. Palu to return the index with the order of the sorted array.
  // return if array is unsortable
  var arr= copyArray(origArr);
  var arrider= copyArray(origArrider);
  
  if (arr.length <= 1){
    return [arr,arrider];
  }

  var less = Array(), greater = Array(), lessrider = Array(), greaterrider = Array();

  // select and remove a pivot value pivot from array
  // a pivot value closer to median of the dataset may result in better performance
  var pivotIndex = Math.floor(arr.length / 2);
  var pivot = (arr.splice(pivotIndex, 1)[0])*1;
  var pivotrider = (arrider.splice(pivotIndex, 1)[0])*1;

  // step through all array elements
  for (var x = 0; x < arr.length; x++){
	arr[x]=arr[x]*1;
    // if (current value is less than pivot),
    // OR if (current value is the same as pivot AND this index is less than the index of the pivot in the original array)
    // then push onto end of less array
    if (
      (arr[x] < pivot)
      ||
      (arr[x] == pivot && x < pivotIndex)  // this maintains the original order of values equal to the pivot
    ){
      less.push(arr[x]);
	  lessrider.push(arrider[x]);
    }

    // if (current value is greater than pivot),
    // OR if (current value is the same as pivot AND this index is greater than or equal to the index of the pivot in the original array)
    // then push onto end of greater array
    else {
      greater.push(arr[x]);
      greaterrider.push(arrider[x]);
    }
  }

  // concatenate less+pivot+greater arrays
  var L=quickSortIndex(less, lessrider);
  var G=quickSortIndex(greater, greaterrider);
  var values=G[0].concat([pivot],L[0]);
  var index= G[1].concat([pivotrider],L[1]);

  return [values,index];
};

function uniqueSorted(arr){
	
	var j=0;
	var newarr=new Array();
	
	newarr[j]=arr[j];
	for (var i=1;i<arr.length;i+=1){
		if (arr[i]!=newarr[j]){
			j=j+1;
			newarr[j]=arr[i];
		}
	}
	return newarr;
}
